<template>
  <el-form ref="previewForm" class="process-form" label-position="top" :rules="rules" :model="_value">
    <div v-for="(item, index) in _forms" :key="item.name + index">
      <el-form-item :prop="item.id" :label="item.title" v-show="showItem(item)">
        <template #label>
          <span>{{ item.title }}</span>
          <el-tooltip :content="item.props.description" placement="top">
            <el-icon v-show="item.props.showDescription"><QuestionFilled /></el-icon>
          </el-tooltip>
        </template>
        <form-design-render
          :ref="`sub-item_${item.id}`"
          v-model="_value[item.id]"
          mode="PC"
          :options-config="item.optionsConfig"
          :config="item"
        />
      </el-form-item>
    </div>
    <!--    <el-form-item>-->
    <!--      <el-button @click="handelSubmit">测试</el-button>-->
    <!--    </el-form-item>-->
  </el-form>
</template>

<script setup>
import { computed, ref, watch, getCurrentInstance, nextTick } from "vue";
import { cloneDeep } from "lodash";
import { CompareFuncs } from "../config/compare/CompareOptions.js";
import FormDesignRender from "./FormDesignRender.vue";
import { QuestionFilled } from "@element-plus/icons-vue";

const props = defineProps({
  forms: {
    type: Array,
    default: () => []
  },
  config: {
    type: Object,
    default: () => {
      return {
        ruleType: "SIMPLE",
        rules: []
      };
    }
  },
  process: {
    type: Object,
    default: () => ({})
  },
  //当前节点，用来联动表单权限
  currentNode: {
    type: String,
    default: null
  },
  instanceId: String,
  modelValue: {
    type: Object,
    default: () => ({})
  },
  mode: {
    type: String,
    default: "PC"
  }
});
const emit = defineEmits(["update:modelValue"]);
const { proxy } = getCurrentInstance();

const formPermHis = ref({});
const validFunc = ref(null);

const _value = computed({
  get() {
    return props.modelValue;
  },
  set(val) {
    emit("update:modelValue", val);
  }
});

const _forms = computed(() => {
  return cloneDeep(props.forms);
});
const rules = computed(() => {
  let rules = {};
  loadFormConfig(_forms.value, rules);
  return rules;
});
const formItemMap = computed(() => {
  const map = new Map();
  loadFormItemMap(_forms, map);
  return map;
});

const showItem = item => {
  return item.perm !== "H";
};
const isReadonly = item => {
  return item.perm === "R";
};
const validate = async call => {
  await nextTick();
  let validateResult = [];
  proxy.$refs.previewForm.validate(valid => {
    if (valid) {
      for (let i = 0, len = _forms.value.length; i < len; i++) {
        validateResult.push(
          new Promise(resolve => {
            resolve(true);
          })
        );
      }
    } else {
      call(valid);
    }
  });
  if (validateResult.length) {
    Promise.all(validateResult).then(results => {
      const isSuccess = results.every(valid => valid === true);
      if (isSuccess) {
        formRuleValid(call);
      } else {
        call(false);
      }
    });
  }
};
const $isNotEmpty = obj => {
  return obj !== undefined && obj !== null && obj !== "" && obj !== "null";
};
const formRuleValid = call => {
  if (props.config.validConfig && $isNotEmpty(props.config.validConfig.js)) {
    if (!validFunc.value) {
      validFunc.value = new Function("ctx", "resolve", "reject", props.config.validConfig.js);
    }
    const ctx = { ..._value.value };
    new Promise((resolve, reject) => {
      validFunc(ctx, resolve, reject);
    })
      .then(() => call(true))
      .catch(err => {
        call(false);
        proxy.$modal.msgWarning(err || "表单规则校验失败，请检查参数");
      });
  } else {
    call(true);
  }
};
const initDefaultValue = formItem => {
  let value = "";
  ["TextInput", "HyperlinkInput", "TextareaInput", "DateTime", "SelectInput", "EditorInput", "TextareaInput"].includes(
    formItem.name
  ) && (value = "");
  ["VoiceToText"].includes(formItem.name) && (value = { txt: "", url: "" });
  ["NumberInput"].includes(formItem.name) && (value = 0);
  ["MultipleSelect", "CascaderInput", "ImageUpload", "FileUpload", "VideoUpload", "UserPicker"].includes(formItem.name) &&
    (value = []);
  return value;
};
const loadFormItemMap = (forms, map) => {
  forms.value.forEach(item => {
    map.set(item.id, item);
  });
};
const addRules = (rules, item) => {
  rules[item.id] = cloneDeep([
    {
      type: getValidType(item),
      required: true,
      message: item.props.validateFailMessage || `请填写${item.title}`,
      trigger: item.props.validateTrigger || "blur"
    }
  ]);
};
const loadFormConfig = (forms, rules) => {
  forms.forEach(item => {
    const value = props.modelValue[item.id] || initDefaultValue(item);
    _value.value[item.id] = item.name === "NumberInput" ? parseFloat(value) : value;
    item.props.required && showItem(item) && addRules(rules, item);
  });
};
const getValidType = item => {
  switch (item.valueType) {
    case "Array":
      return "array";
    case "Number":
      return "number";
    default:
      return undefined;
  }
};
const hideField = id => {
  const field = formItemMap.value.get(id);
  field && (field.perm = "H");
};
const showField = id => {
  const field = formItemMap.value.get(id);
  field && (field.perm = formPermHis.value[id] || "E");
};
const compare = condition => {
  const source = _value.value[condition.field];
  let compareType = null;
  switch (condition.fieldType) {
    case "SelectInput":
      compareType = "strCompare";
      break;
    case "MultipleSelect":
      compareType = "strArrCompare";
      break;
  }
  return CompareFuncs[compareType][condition.compare](
    source,
    condition.fixed ? condition.compareVal : _value.value[condition.compareVal[0]]
  );
};
const parserRule = cdRule => {
  const condition = cdRule.condition;
  try {
    return compare(condition);
  } catch (e) {
    return false;
  }
};
const doActions = async actions => {
  actions?.forEach(action => {
    switch (action.type) {
      case "SHOW":
        action.targets.forEach(tg => showField(tg));
        break;
      case "HIDE":
        action.targets.forEach(tg => hideField(tg));
        break;
    }
  });
};

const analyseRules = async () => {
  props.config?.rules?.forEach(rule => {
    doActions(parserRule(rule.condition) ? rule.action.with : rule.action.other);
  });
};

watch(
  () => props.modelValue,
  () => {
    if (props.config?.rules?.length) {
      if (!Object.keys(formPermHis.value)?.length) {
        formItemMap.value?.forEach(item => {
          formPermHis.value[item.id] = item.perm;
        });
      }
      analyseRules();
    }
  },
  { deep: true, immediate: true }
);

// const handelSubmit = () => {
//   proxy.$refs.previewForm.validate(val => {
//     if (!val) return proxy.$modal.msgError("请填写必填项");
//     console.log(_value.value);
//   });
// };
</script>

<style lang="scss" scoped>
.process-form {
  :deep(.el-form-item) {
    margin-bottom: 15px;
  }
  :deep(.el-form-item__label) {
    padding: 0 0;
  }
}
</style>
